#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include "Task.hpp"
using namespace std;

struct pthreadInfo
{
    pthread_t tid;
    string pthreadname;
};
static const int defaultcap = 5;

template <class T>
class ThreadPool
{
public:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void Wakeup()
    {
        pthread_cond_signal(&cond_);
    }
    void Sleep()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }
    bool IsQueueEmpty()
    {
        return tasks.empty();
    }
    string GetThreadname(pthread_t td)
    {
        for (auto &e : tids)
        {
            if (td == e.tid)
                return e.pthreadname;
        }
        return "None";
    }

public:
    ThreadPool(int cap = defaultcap) : tids(cap)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }
    static void *HandlerTask(void *args)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        while (true)
        {
            tp->Lock();
            while (tp->IsQueueEmpty())
            {
                tp->Sleep();
            }
            Task t = tp->pop();
            tp->Unlock();
            t();
            string name = tp->GetThreadname(pthread_self());
            cout << name << " running, " << "result is " << t.GetResult() << endl;
        }
    }
    void start()
    {
        // 创建进程池里面的进程并执行任务
        for (int i = 0; i < tids.size(); i++)
        {
            tids[i].pthreadname = "thread-" + to_string(i + 1);
            pthread_create(&tids[i].tid, nullptr, HandlerTask, this);
        }
    }
    void push(Task t)
    {
        Lock();
        tasks.push(t);
        Wakeup();
        Unlock();
    }
    Task pop()
    {
        Task t = tasks.front();
        tasks.pop();
        return t;
    }

private:
    vector<pthreadInfo> tids; // 保存线程池里的所有线程
    queue<Task> tasks;        // 保存所有任务

    pthread_mutex_t mutex_; //
    pthread_cond_t cond_;
};